home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / src / vmake / state.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-09  |  28.8 KB  |  928 lines

  1. /*
  2.  *    (c)Copyright 1992-1997 Obvious Implementations Corp.  Redistribution and
  3.  *    use is allowed under the terms of the DICE-LICENSE FILE,
  4.  *    DICE-LICENSE.TXT.
  5.  */
  6. #include "vmake.h"
  7.  
  8. struct Gadget *oldgad;
  9.  
  10. Prototype void handle_hit(struct Gadget *gad,int shift, int doubleclick);
  11. Prototype void set_cyc_state(struct G_CYCLE *cyc,struct G_VALUE *val);
  12. Prototype void handle_list(struct G_LIST *list,struct Gadget *gad,int class,char *buf, int doubleclick);
  13. Prototype void redraw_gadget(struct Gadget *gad);
  14. Prototype void recalc_prop(struct G_LIST *list,UWORD *body,UWORD *sltop);
  15. Prototype int  newpos(struct G_LIST *list,int spos,struct G_ENTRY *ent);
  16. Prototype void set_gadlist(struct GADLIST *gadlist,int state);
  17. Prototype void set_gadgets(int state);
  18. Prototype int  get_work_filename(char *gfname, int spat);
  19. Prototype void mark_clean(void);
  20. Prototype int  test_dirty(void);
  21.  
  22. /***********************************************************************************
  23.  * Procedure: handle_hit
  24.  * Synopsis:  handle_hit(gadget, shift, doubleclick);
  25.  * Purpose:   Handle the processing for the hit on a gadget.
  26.  ***********************************************************************************/
  27. void handle_hit(struct Gadget *gad,
  28.                 int    shift,
  29.                 int    doubleclick
  30.                )
  31. {
  32.    struct G_OBJECT *obj;
  33.  
  34.    obj = (struct G_OBJECT *)gad->UserData;
  35.    /* Ignore any hits on disabled gadgets */
  36.    if ((gad->Flags & GADGHIGHBITS) == GADGHNONE) return;
  37.  
  38.    if (doubleclick)
  39.    {
  40.       if (oldgad != gad)
  41.          doubleclick = 0;
  42.    }
  43.    else
  44.       oldgad = gad;
  45.  
  46. #ifdef DBG_JGM
  47. printf("Double click state = %d\n", doubleclick);
  48. #endif
  49.  
  50.    switch(obj->class)
  51.    {
  52.       case CLASS_STRING:
  53.          break;
  54.       case CLASS_CYCLE:
  55.          {
  56.             /* We need to advance the string to the next state */
  57.             /* When we refresh the gadget, we need to first blank it out */
  58.             struct G_CYCLE *cyc;
  59.             struct G_VALUE *val;
  60.  
  61.             cyc = (struct G_CYCLE *)obj;
  62.             val = cyc->curval;
  63.  
  64.             if (shift)
  65.             {
  66.                for(val = cyc->values;
  67.                    (val->next != NULL) && (val->next != cyc->curval);
  68.                    val = val->next);
  69.             }
  70.             else
  71.             {
  72.                val = val->next;
  73.                if (val == NULL) val = cyc->values;
  74.             }
  75.             set_cyc_state(cyc, val);
  76.             obj->state |= DIRTY_BIT;
  77.          }
  78.          break;
  79.       case CLASS_CHECK:
  80.          obj->state = ((gad->Flags & SELECTED) != 0) & DIRTY_BIT;
  81.          break;
  82.       case CLASS_LIST:
  83.          handle_list((struct G_LIST *)obj, gad, gad->GadgetID, NULL, doubleclick);
  84.          break;
  85.       case CLASS_BUTTON:
  86.          if (!doubleclick) /* don't edit or compile twice for a double click */
  87.             do_command(global.button[obj->state & STATE_MASK].command);
  88.          break;
  89.       default:
  90.          break;
  91.    }
  92. }
  93. /***********************************************************************************
  94.  * Procedure: redraw_gadget
  95.  * Synopsis:  redraw_gadget(gadget);
  96.  * Purpose:   Rerender a gadget on the screen
  97.  ***********************************************************************************/
  98. void redraw_gadget(struct Gadget *gad
  99.                   )
  100. {
  101.    SetBPen(global.rp, 0);
  102.    SetAPen(global.rp, 0);
  103.    RectFill( global.rp, gad->LeftEdge + VBAR, gad->TopEdge + HBAR,
  104.                          gad->LeftEdge + gad->Width - 1 - VBAR,
  105.                          gad->TopEdge + gad->Height - 1 - HBAR);
  106.    RefreshGList( gad, global.window, NULL, 1);
  107. }
  108.  
  109. /***********************************************************************************
  110.  * Procedure: set_cyc_state
  111.  * Synopsis:  set_cyc_state(cyc,val)
  112.  * Purpose:   Set a cycle gadget to a give value
  113.  ***********************************************************************************/
  114. void set_cyc_state(struct G_CYCLE *cyc,
  115.                    struct G_VALUE *val
  116.                   )
  117. {
  118.    struct G_STRING *str;
  119.    struct Gadget *gad;
  120.  
  121.    /* See It is currently being displayed on the screen.  If so, we will have to */
  122.    /* do some cleanup work to get it updated.                                    */
  123.    str = cyc->curval->string;
  124.    if ((str != NULL) && (str->base.gadget != NULL))
  125.    {
  126.       /* If there is a string gadget currently in the cycle gadget, we need */
  127.       /* to free it up                                                      */
  128.       RemoveGList( global.window, str->base.gadget, 1);
  129.       free_gadget(str->base.gadget);
  130.    }
  131.  
  132.    if (val == NULL) return;
  133.  
  134.    cyc->curval = val;
  135.  
  136.    /* Now, if we are currently displaying the gadget, we need to get it on the */
  137.    /* screen.                                                                  */
  138.    if (gad = cyc->base.gadget)
  139.    {
  140.       struct IntuiText *itext;
  141.       struct Gadget *strgad;
  142.       int oldpos;
  143.  
  144.       itext = gad->GadgetText->NextText;
  145.       itext->IText = val->title;
  146.  
  147.       strgad = setup_cycle_gadget(gad, itext, val);
  148.  
  149.       oldpos = RemoveGList(global.window, gad, 1);
  150.       AddGList(global.window, gad, oldpos, 1, NULL);
  151.  
  152.       if (strgad) AddGadget( global.window, strgad, 0);
  153.  
  154.       /* Wipe out the inner area of the gadget so that we can redraw it later */
  155.       redraw_gadget(gad);
  156.       if (strgad) redraw_gadget(strgad);
  157.    }
  158. }
  159.  
  160. /***********************************************************************************
  161.  * Procedure: handle_list
  162.  * Synopsis:  handle_list(list, gadget, int class, buf, doubleclick);
  163.  * Purpose:   Handle the processing for the hit on a list gadget.
  164.  ***********************************************************************************/
  165. void handle_list(struct G_LIST *list,
  166.                  struct Gadget *gad,
  167.                  int class,
  168.                  char *buf,
  169.                  int doubleclick
  170.                 )
  171. {
  172.    struct G_ENTRY *ent, *prevent;
  173.    struct PropInfo *pi;
  174.    int expect;
  175.    int docmnd;
  176.    int pos;
  177.    int prevpos;
  178.    int i;
  179.    int oldpos[MAX_LIST];
  180.  
  181.    static int oldpropidx;
  182.  
  183.    expect = docmnd = 0;
  184.    pos = -1; /* used to indicate no valid selection */
  185.    if (list->sel) /* we should expect a valid selection */
  186.    {
  187.       expect = 1;
  188.       pos = list->base.state & STATE_MASK;
  189.    }
  190.    prevpos = pos;
  191.  
  192.    switch(class & CLASS_MASK) /* Isolate class from subclass */
  193.    {
  194.       case CLASS_ADD:
  195.       {
  196.          int nameinbuf = 0;
  197.          /* Note that gad parameter may not be set on entry. In this case */
  198.          /* if buf parm is set, it has name of file to add, otherwise     */
  199.          /* request a name.  No way to enter a name for Dos 1.3 yet.      */
  200.          if (doubleclick) /* Don't put up requester twice */
  201.             return;
  202.          ent = get_mem(sizeof(struct G_ENTRY));
  203.          if (ent == NULL) 
  204.          {
  205.             request(1, TEXT_NOMEM, NULL, NULL);
  206.             return;
  207.          }
  208.  
  209.          if (buf)
  210.             if (*buf != '\0')
  211.             {
  212.                strcpy(ent->buf, buf);
  213.                nameinbuf = 1;
  214.             }
  215.          if (!nameinbuf)
  216.          {
  217.             if (get_work_filename(ent->buf, CONFIG_FILES) == 0)
  218.             {
  219.                /* User aborted file request, we need to give up too */
  220.                free_mem(ent, sizeof(struct G_ENTRY));
  221.                global.rexxrc = TEXT_CANCEL; /* It's what happened...   */
  222.                return; /* don't mess around with gadgets */
  223.             }
  224.          }
  225.  
  226.          /* we're committed - make sure we select it, whereever we put it */
  227.          expect = 1;
  228.          /* now link the new name into the list */
  229.          if (list->first == NULL)
  230.          {
  231.             int oldpos;
  232.             oldpos = RemoveGList(global.window, list->delgad, 1);
  233.             list->delgad->Flags   &= ~GADGDISABLED;
  234.             AddGList(global.window, list->delgad, oldpos, 1, NULL);
  235.             redraw_gadget(list->delgad);
  236.             list->top = list->first = ent;
  237.             pos = 0; /* select the entry we just added */
  238.          }
  239.          else
  240.          {
  241.             if (pos == -1)  /* if nothing selected, add at top of */
  242.                pos = 0;     /* display - and select it            */
  243.             prevent = list->top;
  244.             for (i = 0; (i < pos) && (prevent != NULL); i++)
  245.                prevent = (struct G_ENTRY *)prevent->base.next;
  246.             /* Insert in front of prevent */
  247.             ent->base.next = (struct G_OBJECT *)prevent;
  248.             if (prevent)
  249.             {
  250.                ent->base.prev = prevent->base.prev;
  251.                prevent->base.prev = (struct G_OBJECT *)ent;
  252.             }
  253.             if (ent->base.prev)
  254.             {
  255.                if (list->top == prevent) list->top = ent;
  256.                ent->base.prev->next = (struct G_OBJECT *)ent;
  257.             }
  258.             else
  259.             {
  260.                list->top = list->first = ent;
  261.             }
  262.             expect = 1;
  263.          }
  264.          /* the list has been changed */
  265.          list->base.state |= DIRTY_BIT;
  266.          break;
  267.       }
  268.       case CLASS_DEL:
  269.          if (doubleclick) /* don't delete two objects by mistake... */
  270.             return;
  271.          if (pos == -1)   /* nothing selected - don't pick one at random...*/
  272.             return;
  273.          ent = list->top;
  274.          for (i = 0; (i < pos) && (ent != NULL); i++)
  275.             ent = (struct G_ENTRY *)ent->base.next;
  276.          /* We want to delete ent */
  277.          if (ent == NULL) return;
  278.          if (ent->base.next)
  279.             ent->base.next->prev = ent->base.prev;
  280.          if (ent->base.prev)
  281.             ent->base.prev->next = ent->base.next;
  282.          else
  283.             list->first = (struct G_ENTRY *)ent->base.next;
  284.  
  285.          /* Update the base pointer so that we are looking at the right space */
  286.          if (list->top == ent)
  287.          {
  288.             list->top = (struct G_ENTRY *)ent->base.next;
  289.             if (list->top == NULL)
  290.                list->top = (struct G_ENTRY *)ent->base.prev;
  291.          }
  292.          free_mem(ent, sizeof(struct G_ENTRY));
  293.          /* the list has been changed */
  294.          list->base.state |= DIRTY_BIT;
  295.          /* and note that we fall through to set state of del gadget */
  296.          goto dodelgad;
  297.          /* except that we want to leave the next item selected - it */
  298.          /* will have moved up to the display position just vacated. */ 
  299.       case CLASS_REFRESH:
  300.          expect = 0;
  301.  
  302. dodelgad:
  303.          {
  304.             int oldpos;
  305.  
  306.             oldpos = RemoveGList(global.window, list->delgad, 1);
  307.             if (list->first == NULL)
  308.                list->delgad->Flags   |=  GADGDISABLED;
  309.             else
  310.                list->delgad->Flags   &= ~GADGDISABLED;
  311.             AddGList(global.window, list->delgad, oldpos, 1, NULL);
  312.             redraw_gadget(list->delgad);
  313.          }
  314.          RefreshGList( list->delgad, global.window, NULL, 5);
  315.          break;
  316.       case CLASS_UP:
  317.          expect = 0; /* trying to move deselects */
  318.          if ((list->top != NULL) && (list->top->base.prev != NULL))
  319.          {
  320.             list->top = (struct G_ENTRY *)list->top->base.prev;
  321.          }
  322.          break;
  323.       case CLASS_DOWN:
  324.          {
  325.             struct G_ENTRY *ent;
  326.             expect = 0; /* trying to move deselects */
  327.             if ((list->top != NULL) && (list->top->base.next != NULL))
  328.             {
  329.                list->top = (struct G_ENTRY *)list->top->base.next;
  330.             }
  331.             ent = list->first;
  332.             i = list->maxent - global.listsize;
  333.             while (ent && i)
  334.             {
  335.                if ((ent = (struct G_ENTRY *)ent->base.next) == list->top) 
  336.                   break;
  337.                i--;
  338.             }
  339.             if ((i == 0) && (ent != NULL))
  340.                list->top = ent;
  341.          }
  342.          break;
  343.       case CLASS_PROP:
  344.          {
  345.             int maxtop;
  346.             expect = 0; /* trying to move deselects */
  347.             pi = (struct PropInfo *)gad->SpecialInfo;
  348.             maxtop = list->maxent - global.listsize;
  349.             i = (pi->VertPot*(2*maxtop))/MAXBODY;
  350.             i = (i + 1)/ 2; /* rounding for more natural button behavior */
  351.             if (i > maxtop) i = maxtop;
  352.             if ((global.mouseprop) && (i == oldpropidx))
  353.             {
  354.                /* don't want to refresh the list unless the view has     */
  355.                /* changed.  Have to refresh the prop gadget or it decays */
  356.                /* all over the border.                                   */
  357.                UWORD body, sltop;
  358.                recalc_prop(list, &body, &sltop);
  359.                NewModifyProp(list->slider, global.window, NULL,
  360.                              AUTOKNOB | FREEVERT | PROPBORDERLESS,
  361.                              0, sltop, MAXBODY, body, 1L);
  362.                return;
  363.             }
  364.             else
  365.                oldpropidx = i;   
  366.             list->top = list->first;
  367.             while((i > 0) && (list->top != NULL))
  368.             {
  369.                list->top = (struct G_ENTRY *)list->top->base.next;
  370.                i--;
  371.             }
  372.             if (list->top == NULL) list->top = list->first;
  373.          }
  374.          break;
  375.       case CLASS_LIST:
  376.          pos = class >> SUBCLASS_OFF;
  377.          expect = 1;
  378.          if (doubleclick)
  379.             docmnd = 1; /* user double clicked on a list entry         */
  380.          break;
  381.       case CLASS_SELECT:
  382.          {
  383.             int spos;
  384.             int simplename;
  385.             struct G_ENTRY *ent;
  386.  
  387.             expect = 0; /* signal nothing to select                    */
  388.             pos = -1; /* nothing selected                              */
  389.             if (buf == NULL) /* no parameter - nothing to do           */
  390.                break;
  391.             if (*buf == '\0') /* empty string not a valid list entry   */
  392.                break;
  393.             /* set pathname true if path separators present, false (or */
  394.             /* NULL) otherwise                                         */
  395.             simplename = (strpbrk(buf, ":/") == NULL);
  396.             ent = list->first;
  397.             spos = 0;
  398.             while (ent)
  399.             {
  400.                char *fnp, *tp;
  401.                fnp = ent->buf;
  402.                if (simplename)
  403.                /* want to match simple name - ignore any path in list entry */
  404.                {
  405.                   tp = strrchr(ent->buf, '/');
  406.                   if (tp == NULL) /* no slash, try for a colon         */
  407.                      tp = strrchr(ent->buf, ':');
  408.                   if (tp != NULL) /* strip off the whole path          */
  409.                      fnp = tp + 1;
  410.                }
  411.                if (stricmp(fnp, buf))
  412.                {
  413.                   /* does not match, step through list                 */
  414.                   ent = (struct G_ENTRY *)ent->base.next;
  415.                   spos++;
  416.                }
  417.                else
  418.                   break;
  419.             }
  420.             if (ent == NULL) /* didn't find a match in the list        */
  421.                break;
  422.             /* we're selected something, now figure out where it goes  */
  423.             expect = 1;
  424.             pos = newpos(list, spos, ent);
  425.          }
  426.          break;
  427.       case CLASS_LTOP:
  428.       case CLASS_LBOT:
  429.          int spos;
  430.          struct G_ENTRY *ent;
  431.  
  432.          ent = list->first; /* tricky: not needed when going to bottom */
  433.          if ((class & CLASS_MASK) == CLASS_LTOP)
  434.             spos = 0;
  435.          else
  436.             spos = list->maxent-1;
  437.          expect = 1;
  438.          pos = newpos(list, spos, ent);
  439.          break;
  440.       case CLASS_LUP:
  441.       case CLASS_LDN:
  442.          int spos;
  443.          struct G_ENTRY *ent, *sent;
  444.  
  445.          sent = list->sel;
  446.          if ((class & CLASS_MASK) == CLASS_LUP)
  447.             sent = (struct G_ENTRY *)sent->base.prev;
  448.          else
  449.             sent = (struct G_ENTRY *)sent->base.next;
  450.          spos = 0;
  451.          ent = list->first;
  452.          while (ent)
  453.          {
  454.             if (ent == sent)
  455.                break;
  456.             ent = (struct G_ENTRY *)ent->base.next;
  457.             spos++;
  458.          }
  459.          expect = 1;
  460.          pos = newpos(list, spos, ent);
  461.          break;
  462.       default:
  463.          printf("Unexpected list gadget class 0x%x\n", class);
  464.          break;
  465.    }
  466.  
  467.    list->sel = NULL;  /* turn off selection & see if we reselect */
  468.  
  469.    gad = list->base.gadget;
  470.  
  471.    if (expect)
  472.    {
  473.       /* Make sure that we are actually in a position to enable the */
  474.       /* requested string gadget.  If not, just ignore the request  */
  475.       /* Start from the top of the display and see if there's an    */
  476.       /* entry at the requested position.                           */
  477.       ent = list->top;
  478.       for(i = pos; ent && (i > 0); i--)
  479.          ent = (struct G_ENTRY *)ent->base.next;
  480.  
  481.       if (ent)
  482.       {
  483.          list->sel = ent;
  484.          }
  485.       else
  486.       {
  487.          pos = -1;
  488.          /* clear out the selected string gadget */
  489.          list->base.state = list->base.state & DIRTY_BIT;
  490.       }
  491.    }
  492.    else
  493.    {
  494.       pos = -1;
  495.    }
  496.    /* point to selected entry gadget if any */
  497.    list->base.state = (list->base.state & DIRTY_BIT) + (pos & STATE_MASK);
  498.  
  499.    /* handle refreshing of LIST hit differently to reduce screen flash   */
  500.    /* and improve response to double click (remove gadget for less time) */
  501.    if ((class & CLASS_MASK) != CLASS_LIST)
  502.    {
  503.       for(i = global.listsize-1; i >= 0; i--)
  504.       {
  505.          oldpos[i] = RemoveGList(global.window, list->btngad[i], 2);
  506.       }
  507.       reset_list_object(list, pos);
  508.  
  509.       /* Wipe out the inner area of the gadget so that we can redraw it later */
  510.       redraw_gadget(gad);
  511.  
  512.       for(i = 0; i < global.listsize; i++)
  513.       {
  514.          AddGList(global.window, list->btngad[i], oldpos[i], 2, NULL);
  515.          RefreshGList( list->btngad[i], global.window, NULL, 2);
  516.       }
  517.    }
  518.    else
  519.    {
  520.       if ((prevpos != -1) && (prevpos != pos))
  521.       /* redraw old button gadget to wipe out the border */
  522.       {
  523.          int oldpos;
  524.          struct Gadget *bgad = list->btngad[prevpos];
  525.          oldpos = RemoveGList(global.window, list->btngad[prevpos], 2);
  526.          list->strgad[prevpos]->GadgetRender = NULL;
  527.          /* standard redraw() misses the edges of the border *sigh*       */
  528.          /* this sizing is a bit slimy and ad hoc but it seems to work... */
  529.          SetBPen(global.rp, 0);
  530.          SetAPen(global.rp, 0);
  531.          RectFill( global.rp, bgad->LeftEdge, bgad->TopEdge + 1,
  532.                    bgad->LeftEdge + bgad->Width - 1,
  533.                    bgad->TopEdge + bgad->Height - 2 + global.listextra);
  534.          AddGList(global.window, list->btngad[prevpos], oldpos, 2, NULL);
  535.          RefreshGList( list->btngad[prevpos], global.window, NULL, 2);     
  536.       }
  537.       if (pos != -1)
  538.       /* draw border for newly selected list gadget */
  539.       {
  540.          int oldpos;
  541.          oldpos = RemoveGList(global.window, list->btngad[pos], 2);
  542.          list->strgad[pos]->GadgetRender = list->sborder;
  543.          AddGList(global.window, list->btngad[pos], oldpos, 2, NULL);
  544.          RefreshGList( list->btngad[pos], global.window, NULL, 2);
  545.       }
  546.    }
  547.  
  548. /* remove to prevent typing into gadget
  549.    if (pos >= 0)
  550.       ActivateGadget(list->strgad[pos], global.window, NULL);
  551. */
  552.  
  553.    {
  554.       UWORD body, sltop;
  555.       recalc_prop(list, &body, &sltop);
  556.       NewModifyProp(list->slider, global.window, NULL,
  557.                     AUTOKNOB | FREEVERT | PROPBORDERLESS,
  558.                     0, sltop, MAXBODY, body, 1L);
  559.    }
  560.  
  561.    if (docmnd && list->sel) /* double clicked on a valid entry */
  562.       do_command(global.text[CONFIG_DCLICK]);
  563. }
  564. /***********************************************************************************
  565.  * Procedure: recalc_prop
  566.  * Synopsis:  recalc_prop(list)
  567.  * Purpose:   Calculate the appropriate BODY and TOP values for a List Prop gadget
  568.  ***********************************************************************************/
  569. void recalc_prop(struct G_LIST *list,
  570.                  UWORD *body, UWORD *sltop
  571.                )
  572. {
  573.    int count, top, maxtop;
  574.    struct G_ENTRY *ent;
  575.  
  576.    count = top = 0;
  577.    ent = list->first;
  578.  
  579.    while(ent != NULL)
  580.    {
  581.       if (ent == list->top) top = count;
  582.       count++;
  583.       ent = (struct G_ENTRY *)ent->base.next;
  584.    }
  585.  
  586.    list->maxent = count;
  587.  
  588.    *body  = MAXBODY;
  589.  
  590.    *sltop = 0;
  591.    if (count > global.listsize)
  592.    {
  593.       *body  = (MAXBODY * global.listsize) / count;
  594.       maxtop = count - global.listsize;
  595.       if (top > maxtop) top = maxtop;
  596.       *sltop = (MAXBODY * top) / maxtop;
  597.    }
  598.  
  599. }
  600. /***********************************************************************************
  601.  * Procedure: newpos
  602.  * Synopsis:  newpos(list, spos, ent)
  603.  * Purpose:   set display position for a new list selection
  604.  *            caller knows both entry & index - why recalculate?
  605.  ***********************************************************************************/
  606. int  newpos(struct G_LIST *list,int spos,struct G_ENTRY *ent)
  607. {
  608.    int j, pos, dtop, maxtop;
  609.    struct G_ENTRY *dent;
  610.  
  611.    maxtop = list->maxent - global.listsize;
  612.  
  613.    /* Now find the index of the top of the visible display      */
  614.    dent = list->first;
  615.    dtop = 0;
  616.    while (dent)
  617.    {
  618.       if (dent == list->top)
  619.       /* We've reached the start of the visible display         */
  620.          break;
  621.       else
  622.       /* keep counting                                          */
  623.       {
  624.          dent = (struct G_ENTRY *)dent->base.next;
  625.          dtop++;
  626.       }
  627.    }
  628.    if ((spos >= dtop) && ((spos - dtop) < global.listsize))
  629.    /* selection is within range of display                      */
  630.    {
  631.       pos = spos - dtop;
  632.    }
  633.    else if (spos <= maxtop)
  634.    /* can move display to start with selected item              */
  635.    {
  636.       list->top = ent;
  637.       pos = 0;
  638.    }
  639.    else
  640.    /* find the lowest possible entry for the top of the display */
  641.    {
  642.       for (j = dtop; j < maxtop; j++)
  643.          list->top = (struct G_ENTRY *)list->top->base.next;
  644.       pos = spos - maxtop;
  645.    }
  646.  
  647.    return pos;            
  648. }
  649. /***********************************************************************************
  650.  * Procedure: set_gadlist
  651.  * Synopsis:  set_gadlist(gadlist,on/off)
  652.  * Purpose:   Enable or Disable all the gadgets in a list
  653.  ***********************************************************************************/
  654. void set_gadlist(struct GADLIST *gadlist,
  655.                  int state
  656.                 )
  657. {
  658.    struct Gadget *gad;
  659.    struct G_CYCLE *cyc;
  660.    int count;
  661.  
  662.    if ((global.window == NULL) ||
  663.        (gadlist == NULL))
  664.       return;
  665.  
  666.    if (state)
  667.    {
  668.       AddGList( global.window, gadlist->gadgets, 30000, gadlist->count, NULL);
  669.    }
  670.    else
  671.    {
  672.       RemoveGList(global.window, gadlist->gadgets, gadlist->count);
  673.    }
  674.  
  675.    for(gad = gadlist->gadgets, count=gadlist->count;
  676.        gad && count;
  677.        gad = gad->NextGadget, count--)
  678.    {
  679.       cyc = (struct G_CYCLE *)gad->UserData;
  680.  
  681.       if ((cyc->base.class & CLASS_MASK) == CLASS_CYCLE)
  682.       {
  683.          set_cyc_state(cyc, state ? cyc->curval : NULL);
  684.       }
  685.       else if (state)
  686.       {
  687.          if ((cyc->base.class & CLASS_MASK) == CLASS_LIST)
  688.          {
  689.             if (gad == cyc->base.gadget)
  690.                handle_list((struct G_LIST *)cyc, NULL, CLASS_REFRESH, NULL, 0);
  691.          }
  692.          else
  693.          {
  694.              RefreshGList(gad, global.window, NULL, 1);
  695.          }
  696.       }
  697.    }
  698. }
  699.  
  700. /***********************************************************************************
  701.  * Procedure: set_gadgets
  702.  * Synopsis:  set_gadgets(on/off)
  703.  * Purpose:   Enable or Disable all gadgets
  704.  ***********************************************************************************/
  705. void set_gadgets(int state)
  706. {
  707.    static int gadliststate;
  708.  
  709.    if (state == gadliststate)
  710.       /* adding or removing twice in a row causes problems */
  711.       return;
  712.    else
  713.    {
  714.       gadliststate = state;
  715.       set_gadlist(global.gadlist,    state);
  716.    }
  717. }
  718.  
  719. /***********************************************************************************
  720.  * Procedure: get_work_filename
  721.  * Synopsis:  type = get_work_filename(gfname, spat)
  722.  * Purpose:   Parse out a file descriptor and return a type for that name
  723.  *            gfname points to a buffer to receive the name.
  724.  *            spat is the index of a search pattern entry in global.text[]
  725.  ***********************************************************************************/
  726. int get_work_filename(char *gfname, int spat)
  727. {
  728.    char *p;
  729.    int len;
  730.    int n;
  731.  
  732.    if (global.inrexx)
  733.    {
  734.       /* whoever called us should have had a filename parameter */
  735.       global.rexxrc = TEXT_BADPARM;
  736.       return 0;
  737.    }
  738.  
  739.    if (global.freq == NULL) return(0);
  740.  
  741.    set_workdir();
  742.    set_busy();
  743.  
  744.    if (AslBase != NULL)
  745.    {
  746.       struct TagItem taglist[9];
  747.  
  748.       n = 0;
  749.  
  750.       taglist[n  ].ti_Tag  = ASL_Pattern;
  751.       taglist[n++].ti_Data = (ULONG)global.text[spat];
  752.  
  753.       taglist[n  ].ti_Tag  = ASL_File;
  754.       taglist[n++].ti_Data = (ULONG)"";
  755.  
  756.       taglist[n  ].ti_Tag  = ASL_Dir;
  757.       taglist[n++].ti_Data = (ULONG)"";
  758.  
  759.       taglist[n  ].ti_Tag  = ASL_Window;
  760.       taglist[n++].ti_Data = (ULONG)global.window;
  761.  
  762. #ifdef ASLFR_DoSaveMode
  763.       taglist[n  ].ti_Tag  = ASLFR_DoSaveMode;
  764.       taglist[n++].ti_Data = FALSE;
  765. #endif
  766.  
  767. #ifdef ASLFR_DoPatterns
  768.       taglist[n  ].ti_Tag  = ASLFR_DoPatterns;
  769.       taglist[n++].ti_Data = TRUE;
  770. #endif
  771.  
  772. #ifdef ASLFR_RejectIcons
  773.       taglist[n  ].ti_Tag  = ASLFR_RejectIcons;
  774.       taglist[n++].ti_Data = TRUE;
  775. #endif
  776.  
  777. #ifdef ASLFR_SleepWindow
  778.       taglist[n  ].ti_Tag  = ASLFR_SleepWindow;
  779.       taglist[n++].ti_Data = TRUE;
  780. #endif
  781.  
  782.       taglist[n  ].ti_Tag  = TAG_DONE;
  783.       taglist[n++].ti_Data = 0;
  784.  
  785.       if (!AslRequest( (APTR)global.freq, taglist))
  786.       {
  787.          set_idle();
  788.          return(0);
  789.       }
  790.    }
  791.    else
  792.    {
  793.        /* We must have arp.library (otherwise we wouldn't have a file     */
  794.        /* Requester structure.)                                           */
  795.        global.freq->rf_Dir[0] = 0;
  796.        global.freq->rf_File[0] = 0;
  797.        if (!ArpFileRequest( global.freq ))
  798.        {
  799.           set_idle();
  800.           return(0);
  801.        }
  802.    }
  803.    set_idle();
  804.  
  805.    n = strlen(global.freq->rf_Dir);
  806.    if (n > 255) n = 255;
  807.    p = gfname;
  808.    memcpy(p, global.freq->rf_Dir, n);
  809.    p += n;
  810.  
  811.    if ((n > 0) && (p[-1] != ':'))
  812.    {
  813.       *p++ = '/';
  814.       n++;
  815.    }
  816.    len = strlen(global.freq->rf_File);
  817.    if (len == 0) return 0; /* null name string equivalent to cancelling */
  818.    if ((n + len) > 255) len = 255-n;
  819.    strncpy(p, global.freq->rf_File, len);
  820.    p[len] = 0;
  821.  
  822.    if (!stricmp(gfname, "ENV"))
  823.       return(FILE_ENV);
  824.  
  825.    len = strlen(gfname);
  826.    p = gfname + strlen(gfname);
  827.  
  828.    if (len < 2)
  829.       return(FILE_OPTIONS);
  830.  
  831.    if ((len >= 7) && (!stricmp(p-7, "DCCOPTS")))
  832.       return(FILE_OPTIONS);
  833.  
  834.    if ((len >= 9) && (!stricmp(p-9, "DMAKEFILE")))
  835.       return(FILE_DMAKEFILE);
  836.  
  837.    if (!stricmp(p-2, ".H"))
  838.       return(FILE_C);
  839.  
  840.    if (!stricmp(p-2, ".C"))
  841.       return(FILE_C);
  842.  
  843.    return(FILE_OPTIONS);
  844. }
  845.  
  846.  
  847. /***********************************************************************************
  848.  * Procedure: mark_clean
  849.  * Synopsis:  mark_clean()
  850.  * Purpose:   reset DIRTY bit for all string objects
  851.  ***********************************************************************************/
  852. void mark_clean(void)
  853. {
  854.    struct G_OBJECT *obj;
  855.    struct G_STRING *strobj;
  856.    #define cycobj ((struct G_CYCLE *)obj)
  857.  
  858.    obj = global.objects;
  859.    while (obj)
  860.    {
  861.       obj->state &= STATE_MASK; /* reset dirt bit for this object */
  862.       if (obj->class == CLASS_STRING)
  863.          strobj = (struct G_STRING *)obj;
  864.       else
  865.       /* see if it's a cycle which might have a string sub-object */
  866.       {
  867.          if (obj->class == CLASS_CYCLE)
  868.             /* strobj may end up NULL.  That's fine               */
  869.             strobj = cycobj->curval->string;
  870.          else
  871.             strobj = NULL;
  872.       }
  873.       if (strobj)
  874.       {
  875.          /* checkpoint present string - safely                    */
  876.      strncpy(strobj->clean_buf, strobj->buf, MAX_STRING);
  877.       }
  878.       obj = obj->next;
  879.    }
  880.    global.dirtysym = 0; /* flags externally defined symbols       */
  881.    #define cycobj
  882. }
  883. /***********************************************************************************
  884.  * Procedure: test_dirty()
  885.  * Synopsis:  bool = test_dirty()
  886.  * Purpose:   set dirty bits for string objects and return true if any dirty
  887.  *            objects are found
  888.  ***********************************************************************************/
  889. int test_dirty(void)
  890. {
  891.    struct G_OBJECT *obj;
  892.    struct G_STRING *strobj;
  893.    int dirty = 0;
  894.  
  895.    obj = global.objects;
  896.    while (obj)
  897.    /* we want to look at everything, not exit on the first dirty object    */
  898.    /* because this routine also flags any dirty string (sub)objects        */
  899.    {
  900.       if (obj->class == CLASS_STRING)
  901.          strobj = (struct G_STRING *)obj;
  902.       else
  903.       {
  904.          /* if it's a cycle, and we haven't changed the pointer, and this  */
  905.          /* entry in the cycle has a string gadget, see if the string has  */
  906.          /* changed.                                                       */
  907.          if ((obj->class == CLASS_CYCLE) && !(obj->state & DIRTY_BIT))
  908.             strobj = ((struct G_CYCLE *)obj)->curval->string;
  909.          else
  910.             strobj = NULL;
  911.       }
  912.       if (strobj)
  913.          if (strcmp(strobj->buf, strobj->clean_buf) != 0)
  914.             /* not the same as the snapshot last time mark_clean() went by */
  915.             obj->state |= DIRTY_BIT; /* easy for anyone else to see now    */
  916.  
  917.       /* whether string object or not, see if it's dirty */
  918.       if (obj->state & DIRTY_BIT)
  919.          dirty = DOSTRUE;
  920.       obj = obj->next;
  921.    }
  922.  
  923.    if (global.dirtysym) /* has user set any private symbols?               */
  924.       dirty = DOSTRUE;
  925.  
  926.    return dirty;
  927. }
  928.